#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/ipc.h>
#include<sys/sem.h>

#include<string.h>
#include<errno.h>


#define FTOK_PATH	"/dev/zero/"
#define FTOK_PROJID	0x22


union semun
{
	int 	val;
	struct	semid_ds *buf;
	unsigned short *array;
};

int semaphore_init(void);
int semaphore_p(int semid);
int semaphore_v(int semid);
void semaphore_term(int semid);


int main(int argc,char **argv)
{
	int	semid;
	pid_t	pid;
	int	i;

	if((semid=semaphore_init())<0)
	{
		printf("Semaphore initial failure: %s\n",strerror(errno));
		return -1;
	}

	if((pid=fork())<0)
	{
		printf("Fork() failure:%s\n",strerror(errno));
		return -2;
	}
	else if(0==pid)
	{
		printf("Child process start to running and do something\n");
		sleep(3);
		printf("Child do something over...\n");
		semaphore_v(semid);

		sleep(1);
		printf("Child process exit now");
		exit(0);
	}

	printf("Parent process P operator wait child process over\n");
	semaphore_p(semid);

	printf("Parent process destroy semathore and exit\n");
	sleep(2);
	printf("Child process exit and ");

	semaphore_term(semid);
	return 0;
}

int semaphore_init(void)
{
	//文件索引值加子序号
	key_t		key;
	int		semid;
	union semun	sem_union;

	if((key=ftok(FTOK_PATH,FTOK_PROJID))<0)
	{
		printf("semget() get IPC failure: %s\n",strerror(errno));
		return -1;
	}

	//创建或获得一个信号量
	semid=semget(key,1,IPC_CREAT|0644);
	if(semid<0)
	{
		printf("semget() get semid failure:%s\n",strerror(errno));
		return -2;

	}
	sem_union.val=0;

	//用来初始化或者删除信号集
	if(semctl(semid,0,SETVAL,sem_union)<0)
	{
		printf("semctl() set initial value failure:%s\n",strerror(errno));
		return -3;
	}

	printf("Semphore get key_t[0x%dx] and semid[%d]\n",key,semid);
	return semid;
	
}

void semaphore_term(int semid)
{
	union semun	sem_union;

	if(semctl(semid,0,IPC_RMID,sem_union)<0)
	{
		printf("Semctl() delete semaphore ID failure: %s\n",strerror(errno));
	}
}

int semaphore_p(int semid)
{
	struct sembuf _sembuf;
	_sembuf.sem_num=0;
	_sembuf.sem_op=-1;
	_sembuf.sem_flg=SEM_UNDO;// IPS_NOWAIT SEM_UNIDO

	if(semop(semid,&_sembuf,1)<0)
	{
		printf("Setmid P operator failure: %s\n",strerror(errno));
		return -1;
	}

	return 0;
}

int semaphore_v(int semid)
{
	struct sembuf _sembuf;

	_sembuf.sem_num=0;
	_sembuf.sem_op=1;
	_sembuf.sem_flg=SEM_UNDO;

	if(semop(semid,&_sembuf,1)<0)
	{
		printf("Setmid V operator failure: %s\n",strerror(errno));
		return -1;
	}

	return 0;
}
